#include <aos/kernel.h>
#include <fcntl.h>
#include "cli_api.h"
#include "aos/cli.h"
#include "vfs.h"

static void cli_cmd_mkdir(char *pwbuf, int blen, int argc, char **argv)
{
    const char *path = argv[1];
    int ret = aos_mkdir(path);

    aos_cli_printf("aos_mkdir [%s] ret=%d\r\n", path, ret);
}
static struct cli_command mkdir_cmd = {
    .name     = "mkdir",
    .help     = "mkdir <path>",
    .function = cli_cmd_mkdir
};

static void cli_cmd_ls(char *pwbuf, int blen, int argc, char **argv)
{
    const char *path = argv[1];
    aos_dir_t *dp;
    aos_dirent_t *out_dirent;

    dp = (aos_dir_t *)aos_opendir(path);

    if(!dp){
        aos_cli_printf("aos_opendir [%s] fail\r\n", path);
        return;
    }

    aos_cli_printf("items in [%s]:\r\n", path);
    while (1) {
        out_dirent = (aos_dirent_t *)aos_readdir(dp);
        if(!out_dirent){
            break;
        }
        aos_cli_printf("%s\r\n", out_dirent->d_name);
    }

    aos_closedir(dp);
}
static struct cli_command ls_cmd = {
    .name     = "ls",
    .help     = "ls <path>",
    .function = cli_cmd_ls
};

static void cli_cmd_rmdir(char *pwbuf, int blen, int argc, char **argv)
{
    const char *path = argv[1];
    int ret = aos_rmdir(path);

    aos_cli_printf("aos_rmdir [%s] ret=%d\r\n", path, ret);
}

static struct cli_command rmdir_cmd = {
    .name     = "rmdir",
    .help     = "rmdir <path>",
    .function = cli_cmd_rmdir
};

static void cli_cmd_echo(char *pwbuf, int blen, int argc, char **argv)
{
    int fd = -1;
    char *buff = (char*)aos_zalloc(4096);
    int ret;

    if(!buff){
        aos_cli_printf("aos_zalloc err.\n");
        goto exit;
    }

    fd = aos_open(argv[1], O_RDONLY);
    if (fd < 0) {
        aos_cli_printf("aos_open err.\n");
        goto exit;
    }

    while(1){
        buff[0] = 0;
        ret = aos_read(fd, buff, 4096);
        if(ret > 0){
            aos_cli_printf("content len=%d:\r\n", ret);
            aos_cli_printf("%s\r\n", buff);
        }else if(ret == 0){
            aos_cli_printf("==end==\r\n");
            break;
        }else{
            aos_cli_printf("==error==\r\n");
            break;
        }
    }

exit:

    if(buff){
        aos_free(buff);
    }

    if(fd >= 0){
        aos_close(fd);
    }
}
static struct cli_command echo_cmd = {
    .name     = "echo",
    .help     = "echo <path>",
    .function = cli_cmd_echo
};

static void cli_cmd_rm(char *pwbuf, int blen, int argc, char **argv)
{
    const char *path = argv[1];
    int ret = aos_unlink(path);

    aos_cli_printf("aos_unlink [%s] ret=%d\r\n", path, ret);
}

static struct cli_command rm_cmd = {
    .name     = "rm",
    .help     = "rm <path>",
    .function = cli_cmd_rm
};

static void cli_cmd_cat(char *pwbuf, int blen, int argc, char **argv)
{
    int fd = -1;
    int len = strlen(argv[2]);
    char *data = argv[2];

    fd = aos_open(argv[1], O_RDWR | O_CREAT | O_TRUNC);
    if (fd < 0) {
        aos_cli_printf("aos_open err.\n");
        goto exit;
    }

    if(aos_write(fd, data, len) != len){
        aos_cli_printf("aos_write err.\n");
        goto exit;
    }

    aos_cli_printf("aos_write len=%d [%s].\n", len, data);

exit:

    if(fd >= 0){
        aos_close(fd);
    }

}
static struct cli_command cat_cmd = {
    .name     = "cat",
    .help     = "cat <path> <content>",
    .function = cli_cmd_cat
};

static void cli_cmd_touch(char *pwbuf, int blen, int argc, char **argv)
{
    int fd = -1;

    fd = aos_open(argv[1], O_RDWR | O_CREAT | O_TRUNC);
    if (fd < 0) {
        aos_cli_printf("touch file err.\n");
        goto exit;
    }
    aos_cli_printf("%s created.\n", argv[1]);
exit:

    if(fd >= 0){
        aos_close(fd);
    }

}
static struct cli_command touch_cmd = {
    .name     = "touch",
    .help     = "touch <path>",
    .function = cli_cmd_touch
};

int32_t cli_cmd_fs_usage(char *pwbuf, int blen, int argc, char **argv)
{
    int32_t err = -EINVAL;
    float f_bfree = 0;
    float f_blocks = 0;
    float usage_percent = 0;
    struct aos_statfs statfs_buf;

    err = aos_statfs(argv[1], &statfs_buf);
    if (!err) {
        f_bfree = statfs_buf.f_bsize*statfs_buf.f_bfree;
        f_blocks = statfs_buf.f_bsize*statfs_buf.f_blocks;
        usage_percent = ((f_blocks - f_bfree) / f_blocks) * 100;

        // print fs total size, free size
        aos_cli_printf("fs size %lld MBytes, free %lld MBytes, usage %f%%\r\n",
            (long long)statfs_buf.f_bsize*statfs_buf.f_blocks/1024/1024, (long long)statfs_buf.f_bsize*statfs_buf.f_bfree/1024/1024, usage_percent);
    }

    return err;
}

static struct cli_command fs_usage_cmd = {
    .name     = "fs_usage",
    .help     = "fs_usage <path>",
    .function = cli_cmd_fs_usage
};


int fs_cmds_cli_register(void) 
{
    aos_cli_register_command(&mkdir_cmd);
    aos_cli_register_command(&ls_cmd);
    aos_cli_register_command(&rmdir_cmd);
    aos_cli_register_command(&echo_cmd);
    aos_cli_register_command(&rm_cmd);
    aos_cli_register_command(&cat_cmd);
    aos_cli_register_command(&touch_cmd);
    aos_cli_register_command(&fs_usage_cmd);

    return CLI_OK;
}
